package action;

import java.sql.Timestamp;

import org.json.JSONObject;

import bean.WechatCache;
import service.WechatCacheService;
import utils.AppConfig;
import utils.DateTimeUtils;
import utils.HttpsRequest;

public class WechatAccessTokenApi {

    public static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
    
    public static boolean CACHED = false;
    public static String CACHED_ACCESS_TOKEN = null;
    public static Timestamp ACCESS_TOKEN_EXPIRES = null;
    
    private WechatCacheService wechatCacheService;
    
    public void setWechatCacheService(WechatCacheService wechatCacheService) {
        this.wechatCacheService = wechatCacheService;
    }
    
    /**
     * 获取Access_token
     * @return
     */
    public String getAccessToken() {
        // Attempt to get access token from cache
        String token = getAcessTokenFromCache();
        if (token != null) {
            return token;
        }
        
        // attempt to get access token from database
        token = getAccessTokenFromDatabase();
        if (token != null) {
            return token;
        }
        
        // request access token from wechat server
        token = getAccessTokenFromWechatServer();
        return token;
    }
    
    /**
     * Request access token from wechat server
     * @return
     */
    public String getAccessTokenFromWechatServer() {
        String token = null;
        
        // 构造参数
        StringBuilder builder = new StringBuilder();
        builder.append("grant_type=client_credential&")
                .append("appid=").append(AppConfig.APP_ID.trim()).append("&")
                .append("secret=").append(AppConfig.APP_SECRET.trim());
        
        // 请求时间
        Timestamp now = DateTimeUtils.generateTimestamp();
        
        // 获取返回结果
        String response = null;
        try {
            response = HttpsRequest.sendGet(ACCESS_TOKEN_URL, builder.toString());
        } catch (Exception e) {
            response = null;
        }
        
        // 处理返回结果
        if (response == null) {
            // 获取失败
            token = null;
        } else {
            // 解析返回数据
            JSONObject obj = new JSONObject(response);
            if (obj.has("access_token") && obj.has("expires_in")) {
                // 获取成功
                token = obj.getString("access_token");
                int expires = obj.getInt("expires_in");
                
                // 更新ROM Cache
                CACHED_ACCESS_TOKEN = token;
                ACCESS_TOKEN_EXPIRES = new Timestamp(now.getTime() + expires * 1000);
                CACHED = true;
                
                // 更新数据库Cache
                WechatCache cache = new WechatCache(
                        token, new Timestamp(now.getTime() + expires * 1000), null, null, null, null);
                wechatCacheService.saveOrUpdateAccessToken(cache);
            }
        }
        
        return token;
    }

    /**
     * Attempt to get access token from database
     * When get token successfully, update the cache 
     * @return
     */
    private String getAccessTokenFromDatabase() {
        // get last cache from database
        WechatCache cache = wechatCacheService.getLast();
        
        // if the token has been cached, token and expires are exist
        if (cache != null && cache.getAccessToken() != null && cache.getAccessTokenExpires() != null) {
            // and the cached token does not expires
            Timestamp now = DateTimeUtils.generateTimestamp();
            if (cache.getAccessTokenExpires().after(now)) {
                // update the ROM cache
                CACHED = false;
                CACHED_ACCESS_TOKEN = cache.getAccessToken();
                ACCESS_TOKEN_EXPIRES = new Timestamp(cache.getAccessTokenExpires().getTime());
                CACHED = true;
                
                // return the token
                return cache.getAccessToken();
            }
        }
        
        return null;
    }

    /**
     * Attempt to get access token from cache
     * @return
     */
    public String getAcessTokenFromCache() {
        // the token has been cached, token and expires are exist
        if (CACHED && CACHED_ACCESS_TOKEN != null && ACCESS_TOKEN_EXPIRES != null) {
            // and the cached token does not expires
            Timestamp now = DateTimeUtils.generateTimestamp();
            if (ACCESS_TOKEN_EXPIRES.after(now)) {
                return CACHED_ACCESS_TOKEN;
            }
        }
        
        // otherwise
        CACHED = false;
        return null;
    }
}
